#include "Terrain.hpp"
#include "TerrainFactory.hpp"

Terrain::Terrain():
    _width(0),
    _height(0),
    _drawable(NULL),
    _texture(NULL)
{
}

Terrain::Terrain(const int width, const int height, DrawableObject* drawable):
    _width(width),
    _height(height),
    _drawable(drawable),
    _texture(NULL)
{
}

Terrain::~Terrain()
{
    if (_drawable != NULL)
        delete _drawable;
}

void            Terrain::draw()
{
    if (_drawable != NULL)
    {
        if (_texture != NULL)
        {
            _texture->enable();
            _texture->bind();
        }
        _drawable->getShader()->sendUniformData("TextureEnable", (_texture != NULL) ? 1.f : -1.f);
        _drawable->draw();
        if (_texture != NULL)
        {
            _texture->disable();
        }
    }
}

void            Terrain::update()
{
    TerrainFactory::calculateNormals(_drawable, _width, _height);
    _drawable->updateVBO();
}

void                    Terrain::changeTextCoordSystem(const TextureBehaviour behaviour)
{
    VertexAttributes*   vertices = _drawable->getVertices();
    int                 tmp;

    for (int itH = 0; itH < _height; itH++)
    {
        for (int itW = 0; itW < _width; itW++)
        {
            tmp = itH * _width + itW;

            if (behaviour == TEXTURE_EXTEND)
            {
                vertices[tmp].textX = static_cast<float>(itW) / static_cast<float>(_width);
                vertices[tmp].textY = static_cast<float>(itH) / static_cast<float>(_height);
            }
            else
            {
                vertices[tmp].textX = itW % 2;
                vertices[tmp].textY = itH % 2;
            }
            vertices[tmp].textZ = 0;
        }
    }
}

VertexAttributes**      Terrain::findVertices(const unsigned char r, const unsigned char g, const unsigned char b, const unsigned int nbObject)
{
    int                 index;
    VertexAttributes*   attribute;

    attribute = _drawable->findVertex(r, g, b, index);
    if (attribute == NULL)
        return NULL;

    if (nbObject > 1)
    {
        int beginX = index % _width - (nbObject / 2);
        int beginY = index / _width - (nbObject / 2);
        int endX = beginX + (nbObject / 2);
        int endY = beginY + (nbObject / 2);

        beginX = (beginX < 0) ? 0 : beginX;
        beginY = (beginY < 0) ? 0 : beginY;
        endX = (endX > _width) ? _width : endX;
        endY = (endY > _height) ? _height : endY;

        VertexAttributes*   all = _drawable->getVertices();
        VertexAttributes**  result = new VertexAttributes*[nbObject * nbObject];
        unsigned int        itObject = 0;

        for (itObject = 0; itObject < nbObject * nbObject; itObject++)
            result[itObject] = NULL;

        itObject = 0;

        for (int itY = beginY; itY < endY; itY++)
        {
            for (int itX = beginX; itX < endX; itX++)
            {
                result[itObject] = &(all[itY * _width + itX]);
                itObject++;
            }
        }
        return result;
    }
    else
    {
        VertexAttributes**  result = new VertexAttributes*[1];
        result[0] = attribute;
        return result;
    }
}

DrawableObject* Terrain::getDrawable()
{
    return _drawable;
}

void            Terrain::setDrawable(DrawableObject* drawable)
{
    _drawable = drawable;
}

int             Terrain::getWidth() const
{
    return _width;
}

void            Terrain::setWidth(const int width)
{
    _width = width;
}

int             Terrain::getHeight() const
{
    return _height;
}

void            Terrain::setHeight(const int height)
{
    _height = height;
}

void            Terrain::setDimensions(const int newWidth, const int newHeight)
{
    _width = newWidth;
    _height = newHeight;
}

Texture*        Terrain::getTexture()
{
    return _texture;
}

void            Terrain::setTexture(Texture* texture)
{
    _texture = texture;
    if (_texture != NULL)
    {
        changeTextCoordSystem(_texture->getBehaviour());
        update();
    }
}
